package org.davidliebman.android.awesomecube;

import java.util.ArrayList;
import java.util.Date;

import javax.microedition.khronos.opengles.GL10;

import android.util.Log;
import android.content.*;
import android.opengl.GLU;

public class MeshList extends Mesh{
	
	public OrientationArray mChildren = new OrientationArray();
	public Integer mTileTemp [][][] = new Integer[6][3][3];
	public Pad mPads ;
	public Mirror mMirror ;
	//public Picking mPicker;
	
	public GL10 mGl;
	//animation vars
	public int mAngleLim = 360;
	
	public Positioning mPosition = new Positioning();
	public Positioning mTilt = new Positioning();
	public int mAngle = 0;
	public int mStep = 15;
	public boolean mUseTurningAnimation = true;
	public boolean mUseSecondTurningAnimation = true;
	public boolean mDisplayAtAngle = false;
	public int mDirection = 0;
	public int mAnimationAxis = 0;
	public int mChosenMove = OrientationArray.MOVE_NONE;
	public int mScreenX, mScreenY ;
	
	public static final int AXIS_X = 0;
	public static final int AXIS_Y = 1;
	public static final int AXIS_Z = 2;
	
	public static final int ANIMATION_NONE = 0;
	public static final int ANIMATION_INCREASING = 1;
	public static final int ANIMATION_DECREASING = 2;
	public static final int ANIMATION_FINISH_ONLY = 3;
	
	public static final int LIMIT_90 = 90;
	public static final int LIMIT_180 = 180;
	public static final int LIMIT_360 = 360;
	public static final int STEP_15 = 15;
	public static final int STEP_90 = 90;
	
	public static final float DEFAULT_Z = -8.0f;
	public static final float DEFAULT_SCREEN_RATIO = 1.4f;
	
	public UsedXYZ mXYZ = new UsedXYZ();
	public PointXYZ mVec = new PointXYZ(0,0,0);
	public boolean mUsePicking = false;
	public boolean mUseMirror = true;
	public boolean mUseTilt = false;
	public boolean mShouldFlash = false;
	private boolean mDebugTouchScreen = false;
	
	// prepare timer 
	private static long FRAMES_PER_SEC = 2;
	private static final long SKIP_TICKS = 1000 / FRAMES_PER_SEC;
	private long ticksElapsed; 
	private long sleepTime = 0;
	private long nextGameTick = 0;
	
	
	public MeshList(Context c) {
		super(c);
		
		mPads = new Pad(c, mGl);
		mMirror = new Mirror(c);
		
		this.mP4.rz = 20;
		this.setDisplayAngle();

		this.mP4.z = MeshList.DEFAULT_Z;//-8.0f;
	}
	
	@Override
	public void draw(GL10 gl) {

		
		mGl = gl;
		this.enableDraw(gl);
		
		this.buildTextures(gl);
		this.animate(gl);
		
		this.scalePerspective(gl);
		
		this.setDisplayAngle();

		if (mDirection == MeshList.ANIMATION_NONE  &&  mDisplayAtAngle) {
			mPads.usePicking(mUsePicking);
			// paint pads once with special colors for 'picking'
			for (int i = 0; i < mPads.size(); i ++ ) {
				mPads.get(i).mLibrary = this.mLibrary;
				mPads.render(gl, i, mVec);
								
			}
			if (! mDebugTouchScreen ) {
				mPads.usePicking(false);
				// paint pads again immediately with texture.
				for (int i = 0; i < mPads.size(); i ++ ) {
					mPads.get(i).mLibrary = this.mLibrary;
					mPads.render(gl, i, mVec);
					
				}
			}
		}
		
		if (mDirection == MeshList.ANIMATION_NONE && ! mDisplayAtAngle && mUseMirror && mUseTilt) {
			mMirror.mirrorTiles(this.mChildren);
			mMirror.render(gl, this.mLibrary, this.mTilt);
		}
		
		// prepare to draw cube...
		mChildren.setTiles();
		
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j ++) {
				for (int k = 0; k < 3; k ++) {
					
					
					
					
					if (mChildren.get(i, j, k) != null ){// &&( ! this.mUsePicking || ! this.mDisplayAtAngle)) {
						
					
						mChildren.get(i,j,k).mShouldLoadArrays = true;
						
						 						
						//pass library object to child Mesh.
						mChildren.get(i,j,k).mLibrary = this.mLibrary;
												
						
						if ( (mDirection != MeshList.ANIMATION_NONE) && 
								(i == mXYZ.mX || mXYZ.mX == UsedXYZ.ALL ) && 
								(j == mXYZ.mY || mXYZ.mY == UsedXYZ.ALL) && 
								(k == mXYZ.mZ || mXYZ.mZ == UsedXYZ.ALL)) {
							this.animatePiece(gl, i, j, k);
						}
						else mChildren.get(i, j, k).mP4 = new Positioning();

						gl.glPushMatrix();
						

						mChildren.get(i,j,k).scaleAndRotateP0(gl);//
						
						mChildren.get(i, j, k).buildMesh(gl);

				
						gl.glPopMatrix();

					}
						
				}
			}
			
		}
		
	
		
		this.disableDraw(gl);
	}

	
	public void animate(GL10 gl ){
	
		if(mTilt.rx != 0 || mTilt.ry != 0) {
			mChildren.setViewingAngle(mTilt);
			mUseTilt = true;
		}
		
		if (this.mDirection == MeshList.ANIMATION_FINISH_ONLY || this.mChildren.mInput.size() > 0) { 
			this.mChildren.finishMovePieces(mTileTemp);
			this.mAngle = 0;
			this.mUseSecondTurningAnimation = false;

			this.mPosition = new Positioning();
			this.mDirection = MeshList.ANIMATION_NONE;
		}
		
		if (this.mDirection == MeshList.ANIMATION_NONE ) {
			//dequeue next move
			if(this.mChildren.hasQueueMembers()) {
				this.mChildren.movePieces();

			}
			else this.mDirection = MeshList.ANIMATION_NONE;
		}
		
		if (this.mDirection == MeshList.ANIMATION_INCREASING) {
			this.mUseTilt = false;
			mAngle = mAngle + mStep;// MeshList.STEP;
			if (mAngle > mAngleLim || this.mChildren.mInput.size() > 1) {
				this.mDirection = MeshList.ANIMATION_NONE;
				mChildren.finishMovePieces( mTileTemp);
				this.mPosition = new Positioning();
				if (this.isSmallPartOfCube()) this.mChildren.checkIfSolved();
				if (this.mUseSecondTurningAnimation && this.mUseTurningAnimation && ! mChildren.hasQueueMembers()) {
					startSecondAnimation( this.mTileTemp, new UsedXYZ(UsedXYZ.ALL,UsedXYZ.ALL,UsedXYZ.ALL), 
							MeshList.ANIMATION_DECREASING, MeshList.AXIS_Y, MeshList.LIMIT_360, MeshList.STEP_15);
					this.mUseSecondTurningAnimation = false;
				}
			}
				
		}
		
		if (this.mDirection == MeshList.ANIMATION_DECREASING) {
			this.mUseTilt = false;
			mAngle = mAngle - mStep;//MeshList.STEP;
			if (mAngle < mAngleLim || this.mChildren.mInput.size() > 1) {
				this.mDirection = MeshList.ANIMATION_NONE;
				mChildren.finishMovePieces( mTileTemp);
				this.mPosition = new Positioning();
				if (this.isSmallPartOfCube()) this.mChildren.checkIfSolved();
				if (this.mUseSecondTurningAnimation && this.mUseTurningAnimation && ! mChildren.hasQueueMembers()) {
					startSecondAnimation(this.mTileTemp, new UsedXYZ(UsedXYZ.ALL,UsedXYZ.ALL,UsedXYZ.ALL), 
							MeshList.ANIMATION_DECREASING, MeshList.AXIS_Y, MeshList.LIMIT_360, MeshList.STEP_15);
					this.mUseSecondTurningAnimation = false;
				}
			}
			
			
		}
		boolean mFlashTest = this.shouldFlash();
		
		if (mFlashTest && this.mShouldFlash) {
			mPads.setShouldFlash(true);
		}
		else if (mFlashTest && ! this.mShouldFlash) {
			mPads.setShouldFlash(false);
		}
		if (mFlashTest) mShouldFlash = ! mShouldFlash;


	}
	
	public void animatePiece(GL10 gl , int mx, int my, int mz){

		this.mPosition = new Positioning();
		if(mAnimationAxis == MeshList.AXIS_X) {
			this.mPosition.rx = this.mAngle;
		}
		if(mAnimationAxis == MeshList.AXIS_Y) {
			this.mPosition.ry = this.mAngle;
		}
		if(mAnimationAxis == MeshList.AXIS_Z) {
			this.mPosition.rz = this.mAngle;
		}
		
		
		if (this.mDirection != MeshList.ANIMATION_NONE ) {
			this.mChildren.get(mx,my,mz).mP2 = this.mPosition;

		}
		else {
			this.mChildren.get(mx, my, mz).mP2 = new Positioning();
		}



	}

	public void startAnimation(  Integer [][][] mTileTemp, UsedXYZ mUsed, int mDirection, int mAxis, int mLimit , int mStep) {
		this.mDirection = mDirection;
		
		if (mDirection == MeshList.ANIMATION_DECREASING) {
			this.mAngle = 0;
			this.mAngleLim = 0  - mLimit;
		}
		else if (mDirection == MeshList.ANIMATION_INCREASING) {
			this.mAngle = 0;
			this.mAngleLim = mLimit;
		}

		this.mAnimationAxis = mAxis;
		this.mXYZ = mUsed;
		if (this.mChildren.hasQueueMembers()) {
			this.mStep = MeshList.STEP_90;
			this.mDirection = MeshList.ANIMATION_FINISH_ONLY;
		}
		else {
			this.mStep = mStep;
		}
	
		this.mPosition = new Positioning();
		this.mTileTemp = mTileTemp;
		this.mUseSecondTurningAnimation = true;
	}
	

	public void startSecondAnimation(  Integer [][][] mTileTemp, UsedXYZ mUsed, int mDirection, int mAxis, int mLimit, int mStep) {
		if (! this.mUseTurningAnimation) return;
		if ( this.mDirection != MeshList.ANIMATION_NONE) return;
		this.mDirection = mDirection;

		if (mDirection == MeshList.ANIMATION_DECREASING) {
			this.mAngle = 0;
			this.mAngleLim = 0  - mLimit;
		}
		else if (mDirection == MeshList.ANIMATION_INCREASING) {
			this.mAngle = 0;
			this.mAngleLim = mLimit;
		}

		this.mAnimationAxis = mAxis;
		this.mXYZ = mUsed;
		this.mStep = mStep;
		this.mPosition = new Positioning();
		this.mTileTemp = mTileTemp;
	}
	
	public void add(Mesh object, int x, int y, int z) {
		mChildren.add(object , x, y, z);
	}

	
	public void clear() {
		mChildren = new OrientationArray();
	}

	public Mesh get(int x, int y, int z) {
		return mChildren.get(x,y,z);
	}

	public void setTilt( Positioning mP) {
		mTilt = mP;
	}
	
	public void setUseDisplayAtAngle( boolean mUse ) {
		mDisplayAtAngle = mUse;
	}
	
	public void setDisplayAngle() {
		int mAngle = 0;
		if (this.mDisplayAtAngle)	{
			mAngle = 45;
			mP4.rz = 0;
			this.mP4.z = MeshList.DEFAULT_Z - getDepthChange(); // -8.0f;

		}
		else {
			mAngle = 0;
			mP4.rz = 20;
			this.mP4.z = MeshList.DEFAULT_Z;//-8.0f;
		}
	
		mP4.rx = mAngle;
		mP4.ry = mAngle;
	}
	
	public float getDepthChange() {
		float mReturn = 0;
		float mScreenRatio = (float)mScreenY/(float)mScreenX;
		//Log.e("MeshList", "screen " + mScreenY + "/"+ mScreenX +":" + mScreenRatio	 );
		
		mReturn = (mScreenRatio - DEFAULT_SCREEN_RATIO) * 4.0f;
		return mReturn;
	}
	
	public boolean isSmallPartOfCube() {
		if (mXYZ.mX == UsedXYZ.ALL && mXYZ.mY == UsedXYZ.ALL && mXYZ.mZ == UsedXYZ.ALL) {
			return false;
		}
		else return true;
	}
	
	public boolean shouldFlash() {
		boolean mMakeSwitch = false;
		Date newDate = new Date();
		ticksElapsed = newDate.getTime();
		sleepTime = nextGameTick - ticksElapsed;
		if ( sleepTime >= 0 ) {
			//Log.e("MeshList", "---Passing time");
		}
		else {
			//Log.e("MeshList", "make switch ---------------------");
			newDate = new Date();
			nextGameTick = newDate.getTime() + SKIP_TICKS;
			mMakeSwitch = true;
		}
		
		return mMakeSwitch;
	}
	
	public void wipeTiles() {
		
		for (int f = 0; f < 6; f ++) {
			for (int x = 0; x < 3; x ++) {
				for (int y = 0; y < 3; y ++) {
					switch(f) {
					case 0: mTileTemp[f][x][y] = TextureLibrary.YELLOW; break;
					case 1: mTileTemp[f][x][y] = TextureLibrary.WHITE; break;
					case 2: mTileTemp[f][x][y] = TextureLibrary.RED; break;
					case 3: mTileTemp[f][x][y] = TextureLibrary.ORANGE; break;
					case 4: mTileTemp[f][x][y] = TextureLibrary.BLUE; break;
					case 5: mTileTemp[f][x][y] = TextureLibrary.GREEN; break;

					}
					//mTile[f][x][y] = f;
				}
			}
		}
		
	}
	
}
